package com.heo.util;

import java.util.Date;
import java.util.concurrent.ConcurrentHashMap;

import org.apache.log4j.Logger;

public class SequenceHelper
{
  private static Logger log = Logger.getLogger(SequenceHelper.class);

  private static Integer defaultId = 0x0001;

  private static final int TIME_OUT = 1 * 60 * 60 * 1000;// 超时时间，当超过这个时间不访问，则剔除。单位：毫秒
  private static final int DETECT_TIME = 10 * 60 * 1000;// 每10分钟检测一次。

  private static ConcurrentHashMap<String, CacheEntity> map = new ConcurrentHashMap<String, CacheEntity>();

  private static class CacheEntity
  {
    private Integer sequenceId = defaultId;// 保存的数据
    private long timeOut = TIME_OUT;// 超时的时间
    private long lastRefeshTime = new Date().getTime();// 最后一次刷新时间

    public Integer getSequenceId()
    {
      return sequenceId;
    }

    public void setSequenceId(Integer sequenceId)
    {
      this.sequenceId = sequenceId;
    }

    public long getTimeOut()
    {
      return timeOut;
    }

    public void setTimeOut(long timeOut)
    {
      this.timeOut = timeOut;
    }

    public long getLastRefeshTime()
    {
      return lastRefeshTime;
    }

    public void setLastRefeshTime(long lastRefeshTime)
    {
      this.lastRefeshTime = lastRefeshTime;
    }
  }

  static
  {
    // 启动一个检测过期的线程，每分钟检测一次。
    new Thread()
    {
      public void run()
      {
        while (true)
        {
          try
          {
            for (String key : map.keySet())
            {
              CacheEntity cache = map.get(key);
              if (cache == null)
              {
                continue;
              }
              if ((new Date().getTime() - cache.getLastRefeshTime()) > cache.getTimeOut())
              {
                log.debug("删除过期的sequence [KEY]" + key);
                map.remove(key);
              }
            }
            Thread.sleep(DETECT_TIME);
          }
          catch (InterruptedException e)
          {
            e.printStackTrace();
            log.error(e.getMessage(), e);
          }
        }
      }
    }.start();
  }

  public synchronized static short getId(String deviceIMEI)
  {
    CacheEntity cache = map.get(deviceIMEI);
    if (cache == null)
    {
      cache = new CacheEntity();
      map.put(deviceIMEI, cache);
      return (short) cache.getSequenceId().intValue();
    }
    else
    {
      Integer sequenceId = cache.getSequenceId() + 1;
      if (sequenceId > 0xFFFF)
      {
        sequenceId = defaultId;
      }
      cache.setLastRefeshTime(new Date().getTime());
      cache.setSequenceId(sequenceId);
      map.put(deviceIMEI, cache);
      return (short) sequenceId.intValue();
    }
  }

  public synchronized static void removeId(String deviceIMEI)
  {
    map.remove(deviceIMEI);
  }

  public static void main(String[] args)
  {
    for (int i = 0; i < 65538; i++)
    {
      System.out.println(ByteHelper.shortToHexString(SequenceHelper.getId("abc")));
    }
  }
}
